HI,這是演算法挑戰挑戰的第二篇,我這個人習慣有求必應,所以這篇就來解解SQL的題目吧!
題目名稱:Department Highest Salary
難易度:中
題目內容:從Employee
和Department
兩張資料表中查詢出各部門領最高薪水的人及金額。
例如:Employee
表內容:
Id | Name | Salary | DepartmentId |
---|---|---|---|
1 | Joe | 70000 | 1 |
2 | Henry | 80000 | 2 |
3 | Sam | 60000 | 2 |
4 | Max | 90000 | 1 |
Department 表內容: |
|||
Id | Name | ||
------------- | ------------- | ||
1 | IT | ||
2 | Sales | ||
查詢結果: | |||
Department | Employee | Salary | |
------------- | ------------- | ------------- | |
IT | Max | 90000 | |
Sales | Henry | 80000 | |
那以下開始動工: |
/*SELECT資料欄位*/
SELECT d.Name AS Department ,e.Name Employee ,s.salary
/*以部門為主檔*/
FROM Department d
LEFT JOIN
/*找出各部門的最高薪水*/
(SELECT MAX(Salary) Salary ,DepartmentId
FROM Employee
GROUP BY DepartmentId) s
/*用部門編號取得部門名稱*/
ON s.DepartmentId = d.Id
/*連結員工資料表*/
LEFT JOIN Employee e
/*用在哪個部門,以及該最高薪水找出對應的人名*/
ON e.DepartmentId = s.DepartmentId AND e.Salary=s.Salary
/*如果有該部門但沒有人員會回傳NULL,所以這時候把他過濾掉*/
WHERE s.salary IS NOT NULL
嘛...雖然我是用這個方式串出來了,但是其實我在下SQL的時候除非跑得特別慢,不然我都不會去注意到效能的問題,也沒有認真研究過怎麼處理資料會比較好,只想著最後出現是我要的就好,如果出現不了再從程式下手,所以我在SQL解題的時候通常都會硬湊,如果看到我的解題方式,有哪裡可以改進的,再麻煩各位大大留言告訴我,我會在今後的寫法一一嘗試的
另外如果寫法有誤或有什麼問題,也都可以告訴我,我在盡速修正,謝謝大家!
晚上試作了一下,
我的解法也跟你一樣...
哈哈哈,我們都一樣,英雄所見略同
我下SQL時也不會特別注意效能問題,原因是因為專案型的案子業務接進來時,DB都已經不知道經過幾手了,資料本身有些就很悲劇了,能撈出PM要的資料就"阿彌陀佛"了!所以公司才要導入Spark來整理來自各廠DB的資料!
哈哈,真的欸!
其實只要資料不要跑得很久,我都不會特別去注意到哪種寫法比較好,而且現在有分頁語法,就算效能差也不會一次查很多筆資料,除非是報表
哈哈哈,我也一樣!!
DECLARE @Employee TABLE
(
Id INT,
Name NVARCHAR(50),
Salary INT,
DepartmentId INT
);
DECLARE @Department TABLE
(
Id INT,
Name NVARCHAR(50)
);
INSERT INTO @Employee
(Id, Name, Salary, DepartmentId)
VALUES
(1, N'Joe', 70000, 1),
(2, N'Henry', 80000, 2),
(3, N'Sam', 60000, 2),
(4, N'Max', 90000, 1)
INSERT INTO @Department
(Id, Name)
VALUES
(1, N'IT'),
(2, N'Sales')
SELECT C.Name,
A.Name,
A.Salary
FROM @Employee AS A
LEFT JOIN (
SELECT A.DepartmentId,
MAX(A.Salary) AS Salary
FROM @Employee AS A
GROUP BY A.DepartmentId
) AS B ON B.DepartmentId=A.DepartmentId AND B.Salary=A.Salary
LEFT JOIN @Department AS C ON C.Id=A.DepartmentId
WHERE B.Salary IS NOT NULL
ORDER BY A.DepartmentId
一種工程師的默契,只是主表反過來了,哈哈哈XD
下篇的這個系列我去翻翻看有沒有我覺得很酷的解法分享好了
恩~~我也玩玩了@@~
declare @Employee table(
Id int
,Name nvarchar(50)
,Salary int
,DepartmentId int
)
insert into @Employee
values(1, N'Joe', 70000, 1),(2, N'Henry', 80000, 2),(3, N'Sam', 60000, 2),(4, N'Max', 90000, 1)
declare @Department table(
Id int
,Name nvarchar(50)
)
insert into @Department
values(1, N'IT'),(2, N'Sales')
select Name,Salary
from (
select Row_Number() Over(Partition by a.Id Order by b.Salary desc) as Sort
,a.Name
,b.Salary
from @Department as a
left join @Employee as b on a.Id = b.DepartmentId
) as k
where Sort = 1
第二種...像這樣吧
select a.Name
,isNull((
select top 1 Salary
from @Employee as b
where a.Id = b.DepartmentId
order by Salary desc
),0) as Salary
from @Department as a
這樣也行..
select a.Name
,isNull((
select max(Salary)
from @Employee as b
where a.Id = b.DepartmentId
),0) as Salary
from @Department as a
如果是T-SQL寫法的話~應該是這樣吧XD..
declare @Detail table(
Department_Name nvarchar(50)
,Employee_Name nvarchar(50)
,Salary int
)
declare @i int,@Max int
declare @Index int,@Department_Name nvarchar(50)
declare @Employee_Name nvarchar(50),@Salary int
set @i = 1
select @Max = isNull(count(*),0)
from @Department
while(@i<=@Max)
begin
select @Index=Id
,@Department_Name=Name
from (
select Row_Number() Over(order by Id) as Sort
,Id
,Name
from @Department
) as k
where Sort = @i
select top 1
@Employee_Name=Name
,@Salary=Salary
from @Employee
where DepartmentId = @Index
order by Salary desc
insert into @Detail
values(@Department_Name,@Employee_Name,@Salary)
set @Employee_Name = ''
set @Salary = 0
set @i = @i +1
end
select * from @Detail
這個我參考darwin0616分享的方式改寫的~也是可以用這方式@@...
SELECT
b.Name AS 'Department',
a.Name AS 'Employee',
Salary
FROM
@Employee as a
JOIN
@Department as b ON a.DepartmentId = b.Id
WHERE
exists(
select *
from @Employee as c
where c.DepartmentId = b.Id
having MAX(c.Salary) = a.Salary
)
哦!有不同的方式了!
先做分組查詢,在把編號為1的資料撈出來,
不曉得還能不能看到其他解法
恩..再多弄了一種...@@a
可是這會不會還必須再另外寫一個子查詢才能找出員工姓名
嗯~的確有2個欄位以上~子查詢不適合~
還是我原來那個查詢是可以帶多個欄位顯示
多玩了一個比較麻煩寫法@@~
用T-SQL的方式來寫..
其實我不太曉得T-SQL和一般的SQL有什麼不一樣
是指用類似程式的處理方式嗎?
對~可以用程式方式的寫法~
你可以看維基的介紹
https://zh.wikipedia.org/wiki/Transact-SQL
哈哈哈,感謝大大
如果會T-SQL應該就可以自己寫很多的預存函式和可程式性來使用了,可惜我還無法
這個我參考darwin0616分享的方式改寫的~
也是可以用這Exists方式@@...
哇哇,到T-SQL的領域內我就完全看不懂了,感覺大大很專精SQL這方面,是工作中常常接觸到複雜的資料處理訓練出來的嗎
@@..基本算是全方位工程師啦...系統架設、程式開發、美工製作都自己來..
在台南一間小補習班...
老闆想做什麼報表分析~是這樣練出來的~求查資料快~不斷的改良SQL..
我也在台南耶!!!!這世界有夠小的
哈哈..
遇見同鄉人太興奮了,哈哈哈,
不過連美工製作都自己來也太...
用Postgresql 來玩玩
create table dept (
id int not null primary key
, name text not null
);
create table emp (
id int not null primary key
, name text not null
, salary int not null
, dept_id int not null references dept(id)
);
insert into dept values
(1, 'IT'), (2, 'Sales');
insert into emp values
(1, 'Joe', 70000, 1),
(2, 'Henry', 80000, 2),
(3, 'Sam', 60000, 2),
(4, 'Max', 90000, 1);
--
select dept_id
, first(name order by salary desc)
, first(salary order by salary desc)
from emp
group by dept_id;
dept_id | first | first
---------+-------+-------
1 | Max | 90000
2 | Henry | 80000
(2 筆資料列)
select d.name Department
, a.employee
, a.salary
from (select dept_id
, first(name order by salary desc) employee
, first(salary order by salary desc) salary
from emp
group by dept_id) a
join dept d
on a.dept_id = d.id;
department | employee | salary
------------+----------+--------
IT | Max | 90000
Sales | Henry | 80000
(2 筆資料列)
哇,IT邦果然高手雲集,哈哈哈,first(salary order by salary desc)
這是類似MSSQL的TOP 1,不過可以只針對一個欄位做排序我覺得還滿厲害的,而且靈活度大大提升
不是只針對一個欄位作排序.....這個你誤會了. top 1 跟這完全不同.
你仔細看我的例子,第1道SQL已經解答出來了,後面只是要取dept的name而已.
不好意思,因為一直沒實際使用過Postgresql,所以以下兩行不能畫上等號ㄛ
first(salary order by salary desc)
(SELECT TOP 1 salary ORDER BY salary DESC)
剛剛稍微查了一下fisrt()回傳數組內第一個資料,感覺有點像但是不知道差異在哪裡
重點在 first(name order by salary desc)
所以first(name order by salary desc)
會影響到後面的那一行結果嗎?first(salary order by salary desc)
這是函數,不是subquery.
哈哈,只是這個函數執行出來的結果好像子查詢
就是結果能一樣,就不必subquery self join.
感謝大大耐心解釋,如果今後用到Postgresql
就可以不用在SELECT
內放一堆子查詢了
解法跟樓主差不多...... (我用MariaDB)
CREATE TABLE IF NOT EXISTS `Employee` (
Id INT(8) NOT NULL AUTO_INCREMENT,
Name VARCHAR(52) NOT NULL,
Salary INT(8) NOT NULL,
DepartmentId INT(8) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `Department` (
Id INT(8) NOT NULL AUTO_INCREMENT,
Name VARCHAR(52) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `Employee`
(Name, Salary, DepartmentId) VALUES
('Joe', 70000, 1),
('Henry', 80000, 2),
('Sam', 60000, 2),
('Max', 90000, 1);
INSERT INTO `Department` (Name) VALUES ('IT'), ('Sales');
SELECT d.Name AS Department, e.Name AS Employee, e.Salary AS Salary FROM `Employee` AS e
RIGHT JOIN (
SELECT MAX(Salary) AS MaxSalary, DepartmentId AS DepId
FROM `Employee`
GROUP BY DepartmentId
) AS m ON e.Salary = m.MaxSalary AND e.DepartmentId = m.DepId
JOIN `Department` AS d ON e.DepartmentId = d.Id
ORDER BY Salary ASC;
第一次看到MariaDB,不過看起來和MYSQL很像
這個解法和二樓的fysh711426大大一樣,話說難道把DepartmentId
部門檔當做主檔的我是異類嗎?哈哈哈。
我 ... ... 直接貼網站的解答公佈官方答案 ... ...
SELECT
Department.name AS 'Department',
Employee.name AS 'Employee',
Salary
FROM
Employee
JOIN
Department ON Employee.DepartmentId = Department.Id
WHERE
(Employee.DepartmentId , Salary) IN
( SELECT
DepartmentId, MAX(Salary)
FROM
Employee
GROUP BY DepartmentId
)
;
條件裡的這一段是我近期才看到的語法,就是一次對多個欄位使用IN語句,不過MSSQL好像無法用這種寫法,讓我非常羨慕MYSQL
(Employee.DepartmentId , Salary) IN
( SELECT
DepartmentId, MAX(Salary)
FROM
Employee
GROUP BY DepartmentId
)
我是用MySQL 想問一下
select d.Name Department,e.Name Employee,MAX(e.Salary) Salary from employee e inner join department d on e.DepartmentId = d.Id GROUP BY e.DepartmentId
輸出的結果跟答案一樣為什麼還是錯誤的回答
我還是新手學生@@
痾 我找到錯誤了 輸出的人不同 不好意思QQ
哈哈,不會啦,
在程式面前人人平等XD
歡迎你每個禮拜如果有題目都來分享做法!
另外,你目前寫法只能帶出這個部門最高薪水,
還要想想辦法才能把該部門領該薪水的人名帶出來,加油啊!